(function (global) {

  var root = global.Rx,
      TestScheduler = root.TestScheduler,
      Observable = root.Observable,

      // Assertions
      CollectionAssert = root.CollectionAssert,

      // Shortcuts for onNext/onError/onCompleted
      onNext = root.ReactiveTest.onNext,
      onError = root.ReactiveTest.onError,
      onCompleted = root.ReactiveTest.onCompleted,
      subscribe = root.ReactiveTest.subscribe;

  /* Tests just basic behavior */
  test('just Basic', function () {
      var scheduler = new TestScheduler();

      // Returns 42 at one tick after subscribe (200)
      var results = scheduler.startScheduler(function () {
          return Observable.just(42, scheduler);
      });

      // Expect a single onNext with 42 and an oncompleted one tick from subscribe
      var expectedMessages = [
          onNext(201, 42),
          onCompleted(201)
      ];

      CollectionAssert.assertEqual(expectedMessages, results.messages);
  });

  /* Tests select method basic behavior */
  test('map Basic', function () {

      var scheduler = new TestScheduler();

      // Creates a hot observable with two messages after subscribe
      var xs = scheduler.createHotObservable(
          onNext(150, 1),
          onNext(210, 2),
          onCompleted(220)
      );

      // Project the hot observable via select without index
      var results = scheduler.startScheduler(function () {
          return xs.map(function (x) { return x + x; });
      });

      // Should get one onNext with 4 and a completed
      var expectedMessages = [
          onNext(210, 4),
          onCompleted(220)
      ];

      CollectionAssert.assertEqual(expectedMessages, results.messages);

      // Should subscribe at 200 and unsubscribe at 220 at last message
      var expectedSubscriptions = [
          subscribe(200, 220)
      ];

      CollectionAssert.assertEqual(expectedSubscriptions, xs.subscriptions);
  });

  /* Tests select method basic behavior */
  test('map Multiple', function () {

    var scheduler = new TestScheduler();

    // Project forward two onNext messages after subscribe and one completed at 220
    var xs = scheduler.createHotObservable(
        onNext(150, 1),
        onNext(210, 2),
        onNext(215, 3),
        onCompleted(220)
    );

    // Project the hot observable via select without index
    var results = scheduler.startScheduler(function () {
      return xs.map(function (x) { return x + x; });
    });

    // Should get one at 210 for 4 and one at 215 for 6 until completed at 220
    var expectedMessages = [
      onNext(210, 4),
      onNext(215, 6),
      onCompleted(220)
    ];

    CollectionAssert.assertEqual(expectedMessages, results.messages);

    // Should subscribe at 200 and unsubscribe at 220 at last message
    var expectedSubscriptions = [
      subscribe(200, 220)
    ];

    CollectionAssert.assertEqual(expectedSubscriptions, xs.subscriptions);
  });

  /* Tests select method empty behavior */
  test('map Empty', function () {

    var scheduler = new TestScheduler();

    // Project forward one onNext after subscribe and one completed at 220
    var xs = scheduler.createHotObservable(
      onNext(150, 1),
      onCompleted(220)
    );

    // Project the hot observable via select without index
    var results = scheduler.startScheduler(function () {
      return xs.map(function (x) { return x + x; });
    });

    var expectedMessages = [
      onCompleted(220)
    ];

    CollectionAssert.assertEqual(expectedMessages, results.messages);

    // Should subscribe at 200 and unsubscribe at 220 at last message
    var expectedSubscriptions = [
      subscribe(200, 220)
    ];

    CollectionAssert.assertEqual(expectedSubscriptions, xs.subscriptions);
  });

  /* Tests select method never firing behavior */
  test('map Never', function () {
    var scheduler = new TestScheduler();

    // Project no messages after subscribe at 200
    var xs = scheduler.createHotObservable(
      onNext(150, 1)
    );

    // Project the hot observable via select without index
    var results = scheduler.startScheduler(function () {
      return xs.map(function (x) { return x + x; });
    });

    // Should expect no messages
    var expectedMessages = [
    ];

    CollectionAssert.assertEqual(expectedMessages, results.messages);

    // Should subscribe at 200 and unsubscribe at 1000 (infinity)
    var expectedSubscriptions = [
      subscribe(200, 1000)
    ];

    CollectionAssert.assertEqual(expectedSubscriptions, xs.subscriptions);
  });

  /* Tests select method where the observable throws an exception */
  test('map Throws', function () {
      var error = new Error('woops');
      var scheduler = new TestScheduler();

      // Project forward one onError after subscribe
      var xs = scheduler.createHotObservable(
          onNext(150, 1),
          onError(210, error)
      );

      var results = scheduler.startScheduler(function () {
          return xs.map(function (x) { return x + x; });
      });

      // Should expect only one message with an error at 210
      var expectedMessages = [
          onError(210, error)
      ];

      CollectionAssert.assertEqual(expectedMessages, results.messages);

      // Should subscribe at 200 and unsubscribe at 210 at point of error
      var expectedSubscriptions = [
          subscribe(200, 210)
      ];

      CollectionAssert.assertEqual(expectedSubscriptions, xs.subscriptions);
  });

  /* Tests select method where the observable throws an exception */
  test('map Selector Throws', function () {
      var error = new Error('woops');
      var scheduler = new TestScheduler();

      // Project forward one onNext after subscribe and one completed at 220
      var xs = scheduler.createHotObservable(
          onNext(150, 1),
          onNext(210, 2)
      );

      var results = scheduler.startScheduler(function () {
          return xs.map(function (x) { throw error; });
      });

      // Should expect only one message with an error at 210
      var expectedMessages = [
          onError(210, error)
      ];

      CollectionAssert.assertEqual(expectedMessages, results.messages);

      // Should subscribe at 200 and unsubscribe at 210 at point of error
      var expectedSubscriptions = [
          subscribe(200, 210)
      ];

      CollectionAssert.assertEqual(expectedSubscriptions, xs.subscriptions);
  });

  /* Tests select method basic behavior */
  test('map With Index Basic', function () {

      var scheduler = new TestScheduler();

      // Project forward one onNext after subscribe and one completed at 220
      var xs = scheduler.createHotObservable(
          onNext(150, 1),
          onNext(210, 2),
          onCompleted(220)
      );

      var results = scheduler.startScheduler(function () {
          return xs.map(function (x, i) { return (x + x) * i; });
      });

      // Should expect one message with 0 and then complettion
      var expectedMessages = [
          onNext(210, 0),
          onCompleted(220)
      ];

      CollectionAssert.assertEqual(expectedMessages, results.messages);

      // Should subscribe at 200 and unsubscribe at 220 at last message
      var expectedSubscriptions = [
          subscribe(200, 220)
      ];

      CollectionAssert.assertEqual(expectedSubscriptions, xs.subscriptions);
  });

}(window));
